package com.mall.system.config;

import org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory;
import org.apache.shardingsphere.infra.config.algorithm.AlgorithmConfiguration;
import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.SQLException;
import java.util.*;

/**
 * ShardingSphere配置类
 * 用于手动配置ShardingSphere数据源，解决自动配置不生效的问题
 */
@Configuration
public class ShardingSphereConfig {
    
    @Value("${spring.shardingsphere.datasource.ds0.jdbc-url}")
    private String ds0JdbcUrl;
    
    @Value("${spring.shardingsphere.datasource.ds0.username}")
    private String ds0Username;
    
    @Value("${spring.shardingsphere.datasource.ds0.password}")
    private String ds0Password;
    
    @Value("${spring.shardingsphere.datasource.ds0.driver-class-name}")
    private String ds0DriverClassName;
    
    @Value("${spring.shardingsphere.datasource.ds1.jdbc-url}")
    private String ds1JdbcUrl;
    
    @Value("${spring.shardingsphere.datasource.ds1.username}")
    private String ds1Username;
    
    @Value("${spring.shardingsphere.datasource.ds1.password}")
    private String ds1Password;
    
    @Value("${spring.shardingsphere.datasource.ds1.driver-class-name}")
    private String ds1DriverClassName;

    /**
     * 创建并配置ShardingSphere数据源
     * 
     * @return DataSource
     * @throws SQLException SQL异常
     */
    @Bean
    @Primary
    public DataSource dataSource() throws SQLException {
        return ShardingSphereDataSourceFactory.createDataSource(
                createDataSourceMap(), 
                Collections.singletonList(createShardingRuleConfiguration()), 
                new Properties());
    }

    /**
     * 创建数据源映射
     * 
     * @return 数据源映射
     */
    private Map<String, DataSource> createDataSourceMap() {
        Map<String, DataSource> dataSourceMap = new HashMap<>();

        // 创建第一个数据源
        HikariDataSource dataSource1 = new HikariDataSource();
        dataSource1.setDriverClassName(ds0DriverClassName);
        dataSource1.setJdbcUrl(ds0JdbcUrl);
        dataSource1.setUsername(ds0Username);
        dataSource1.setPassword(ds0Password);
        dataSourceMap.put("ds0", dataSource1);

        // 创建第二个数据源
        HikariDataSource dataSource2 = new HikariDataSource();
        dataSource2.setDriverClassName(ds1DriverClassName);
        dataSource2.setJdbcUrl(ds1JdbcUrl);
        dataSource2.setUsername(ds1Username);
        dataSource2.setPassword(ds1Password);
        dataSourceMap.put("ds1", dataSource2);

        return dataSourceMap;
    }

    /**
     * 创建分片规则配置
     * 
     * @return 分片规则配置
     */
    private ShardingRuleConfiguration createShardingRuleConfiguration() {
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        
        // 添加表分片规则
        shardingRuleConfig.getTables().add(getUserTableRuleConfiguration());
        shardingRuleConfig.getTables().add(getLogTableRuleConfiguration());
        
        // 添加分片算法
        shardingRuleConfig.getShardingAlgorithms().put("user-table-inline", createTableShardingAlgorithm());
        shardingRuleConfig.getShardingAlgorithms().put("user-db-inline", createDatabaseShardingAlgorithm());
        shardingRuleConfig.getShardingAlgorithms().put("log-table-inline", createLogTableShardingAlgorithm());
        shardingRuleConfig.getShardingAlgorithms().put("log-db-inline", createLogDatabaseShardingAlgorithm());

        return shardingRuleConfig;
    }

    /**
     * 获取用户表分片规则配置
     * 
     * @return 用户表分片规则配置
     */
    private ShardingTableRuleConfiguration getUserTableRuleConfiguration() {
        ShardingTableRuleConfiguration result = new ShardingTableRuleConfiguration("t_system_user", "ds$->{0..1}.t_system_user_$->{0..9}");
        result.setTableShardingStrategy(new StandardShardingStrategyConfiguration("user_id", "user-table-inline"));
        result.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("user_id", "user-db-inline"));
        return result;
    }

    /**
     * 获取日志表分片规则配置
     * 
     * @return 日志表分片规则配置
     */
    private ShardingTableRuleConfiguration getLogTableRuleConfiguration() {
        ShardingTableRuleConfiguration result = new ShardingTableRuleConfiguration("t_system_log", "ds$->{0..1}.t_system_log_$->{0..9}");
        result.setTableShardingStrategy(new StandardShardingStrategyConfiguration("id", "log-table-inline"));
        result.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("id", "log-db-inline"));
        return result;
    }

    /**
     * 创建表分片算法
     * 
     * @return 表分片算法配置
     */
    private AlgorithmConfiguration createTableShardingAlgorithm() {
        Properties props = new Properties();
        props.setProperty("algorithm-expression", "t_system_user_$->{user_id % 10}");
        return new AlgorithmConfiguration("INLINE", props);
    }

    /**
     * 创建数据库分片算法
     * 
     * @return 数据库分片算法配置
     */
    private AlgorithmConfiguration createDatabaseShardingAlgorithm() {
        Properties props = new Properties();
        props.setProperty("algorithm-expression", "ds$->{user_id % 2}");
        return new AlgorithmConfiguration("INLINE", props);
    }

    /**
     * 创建日志表分片算法
     * 
     * @return 日志表分片算法配置
     */
    private AlgorithmConfiguration createLogTableShardingAlgorithm() {
        Properties props = new Properties();
        props.setProperty("algorithm-expression", "t_system_log_$->{id % 10}");
        return new AlgorithmConfiguration("INLINE", props);
    }

    /**
     * 创建日志数据库分片算法
     * 
     * @return 日志数据库分片算法配置
     */
    private AlgorithmConfiguration createLogDatabaseShardingAlgorithm() {
        Properties props = new Properties();
        props.setProperty("algorithm-expression", "ds$->{id % 2}");
        return new AlgorithmConfiguration("INLINE", props);
    }
}